#include <cstddef>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <conio.h>
#include <tgmath.h>
#include <stdio.h>

#include "include\battle.h"
#include "include\entitymanager.h"
#include "include\entity.h"
#include "include\magic.h"


//Begin public methods

BattleAction::BattleAction()
{

}

ActionType BattleAction::GetPlayerAction(Entity *pPlayer)
{
    ActionType thisAction = NOTHING;
    while (thisAction == NOTHING)
    {
        cout << "Select action: (A)ttack, (D)efend, or (C)ast" << endl;
        char inputChar = tolower(getch());
        switch (inputChar)
        {
        case 'a':
            thisAction = ATTACK;
        break;
        case 'c':
            {
                lastMagic = magic(pPlayer);
                SpellType thisSpell = lastMagic.GetPlayerSpell();
                if (lastMagic.canCast(pPlayer, thisSpell))
                {
                    thisAction = CAST;
                }
            }
        break;
        case 'd':
            thisAction= DEFEND;
        break;
        default:
            cout << "Invalid key press" << endl;
        break;
        }

    }
    return thisAction;

}

ActionType BattleAction::GetEnemyAction(Entity *pEnemy) // This is kludgey and will be replaced by a more sane AI
{
    int randomRoll = rand() % 100;
    if (randomRoll < 90 || pEnemy->GetMagic() < 22)
    {
        return ATTACK;
    }
    else
    {
        return CAST;
    }

}

bool BattleAction::ExecuteAction(ActionType action, Entity *pSubject, Entity *pObject)
{
    targetEntity = pObject;
    bool success;
    switch (action)
    {
    case ATTACK:
        success = Attack(pSubject, pObject);
        if (success) {setActionType(ATTACK);}
    break;
    case DEFEND:
        success = Defend(pSubject);
        if (success) {setActionType(DEFEND);}
    break;
    case CAST:
        {
            success = lastMagic.SpellCast(pSubject, pObject);
            if (success) {setActionType(CAST);}
        }
    break;
    default:
        exit(1);
    break;
    }
    return success;
}

bool BattleAction::Attack(Entity *pAttacker, Entity *pTarget)
{
    if (this->Hit(pAttacker, pTarget))
    {
        Damage(pAttacker, pTarget);

    }
    else
    {
        cout << pAttacker->GetName() << " attacks " << pTarget->GetName() << " and misses." << endl;
    }
    return true;
}

bool BattleAction::Defend(Entity *pDefender)
{
    pDefender->SetStatus(DEFENDING, 1, 1);
    cout << pDefender->GetName() << " defends, temporarily raising Dex to " << pDefender->GetDexterity() << endl;
    return true;
}

void BattleAction::setActionType(ActionType type)
{
    thisActionType = type;
}

ActionType BattleAction::getActionType()
{
    return thisActionType;
}

//End public methods, begin private methods

//float BattleAction::LuckModifier(Entity *pAttacker, Entity *pTarget)
//{
//    return 1 + ((float)pAttacker->GetLuck() / 100) - ((float)pTarget->GetLuck( )/ 100);
//}

bool BattleAction::Hit(Entity *pAttacker, Entity *pTarget)
{
   float hitModifier = 1 + ((float)pAttacker->GetDexterity() / 100) - ((float)pTarget->GetDexterity() / 100);

//   #ifdef DEBUG_MODE
//        cout << "Hit chance modifier: " << hitModifier << endl;
//        cout << "Hit Luck modifier: " << LuckModifier(pAttacker, pTarget) << endl;
//   #endif

   float hitRoll = ((rand() % 100) / 100.0f) * hitModifier;
   float hitRollNeeded = .33;

   #ifdef DEBUG_MODE
        cout << "Hit Roll: " << hitRoll ;
        cout << " (Must be greater than " << hitRollNeeded << ")" << endl;
   #endif

   if (hitRoll > hitRollNeeded)
   {
       return true;
   }
   else
   {
       return false;
   }

}

int BattleAction::Damage(Entity *pAttacker, Entity *pTarget)
{
    float modifier = 1 + ((float)pAttacker->GetAttackStrength() / 100) - ((float)pTarget->GetDefenseStrength()/100);

//    #ifdef DEBUG_MODE
//        cout << "Damage modifier: " << modifier << endl;
//        cout << "Luck modifier: " << LuckModifier(pAttacker, pTarget) << endl;
//    #endif

    damage = round((rand()% 20) * modifier ) + 1;
    pTarget->SetHealth(pTarget->GetHealth() - damage);
    cout << pAttacker->GetName() << " attacks " << pTarget->GetName() << " for -" << damage << endl;
    return damage;
}

string BattleAction::GetActionName()
{
    switch (thisActionType)
    {
    case ATTACK:
        return "attack";
    break;
    case DEFEND:
        return "defend";
    break;
    case CAST:
        {
            return string {"the spell "} + lastMagic.GetSpellName();
        }
    break;
    default:
        return "nothing";
    break;
    }
}

string BattleAction::GetActionResultString()
{
    switch (thisActionType)
    {
    case ATTACK:
        return string{"attacked "} + targetEntity->GetName() + " for " + intToString(floor(damage));
    break;
    case DEFEND:
        return "was harder to hit";
    break;
    case CAST:
        {
            return lastMagic.GetSpellEffectString();
        }
    break;
    default:
        return "nothing";
    break;
    }
}

string BattleAction::intToString(int number)
{
    char numberChar[5];
    sprintf(numberChar, "%d", number);
    return string{numberChar};
}

